package com.easy.consumer.component;

import com.alibaba.fastjson.JSON;
import com.easy.common.bean.*;
import com.easy.common.exception.ServiceException;
import com.easy.common.service.*;
import com.easy.common.util.SKRequest;
import com.easy.common.util.SYS;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

@Component
public class SKConsumer {
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @DubboReference
    ISeckillResultService seckillResultService;
    @DubboReference
    ISeckillOrderService seckillOrderService;
    @DubboReference
    ISeckillGoodsService seckillGoodsService;
    @DubboReference
    IGoodsService goodsService;
    @DubboReference
    IOrderAddrService orderAddrService;
    @DubboReference
    IDeliveryAddrService deliveryAddrService;


    /**
     * 监听秒杀请求队列
     * @param message
     *
     *
     *
     */
    @RabbitListener(queues=SYS.SK_QUEUE)//监听秒杀请求队列   监听者设计模式 被监听者有一个集合,记录监听者
    public void consumerMessage(String message){
        try {
            //将队列中的JSON转换成SKRequest对象
            SKRequest skRequest = JSON.parseObject(message, SKRequest.class);
            System.out.println("秒杀请求：" + skRequest);
            //判断是否有秒杀商品存在
            ValueOperations vos = redisTemplate.opsForValue();//处理字符串值
            HashOperations hos =redisTemplate.opsForHash();//处理hash值
            SetOperations sos = redisTemplate.opsForSet();//处理set值
            //秒杀商品的key
            Integer skgoodsid = skRequest.getSkgoodsid();
            System.out.println("秒杀商品id：" + skgoodsid);
            String sk_goods_key = SYS.SK_PRE_GOODS_KEY + skgoodsid;//redis中存储的秒杀商品的key对应val
            System.out.println("秒杀商品key：" + sk_goods_key);
            //秒杀活动的key
            Integer activityid = skRequest.getActivityid();
            String sk_activity_key = SYS.SK_PRE_ACTIVITY_KEY + activityid;
            System.out.println("秒杀活动key：" + sk_activity_key);
            //用户选择的收货地址id
            Integer delivery_addr_id = skRequest.getDelivery_addr_id();

            boolean hasActivity = redisTemplate.hasKey(sk_activity_key);//检查是否有这个key
            int activity_status = Integer.parseInt(String.valueOf(hos.get(sk_activity_key,SYS.SK_ACTIVITY_STATUS_HASH_KEY)));//秒杀活动存的hash值，有三个属性，活动状态，开始时间，结束时间
            long activity_start_time = Long.parseLong(String.valueOf( hos.get(sk_activity_key,SYS.SK_ACTIVITY_START_TIME_KEY)));
            long activity_end_time = Long.parseLong(String.valueOf(hos.get(sk_activity_key,SYS.SK_ACTIVITY_END_TIME_KEY)));
            if(!hasActivity||activity_status!=1||System.currentTimeMillis()<activity_start_time||System.currentTimeMillis()>activity_end_time){
                //活动不存在||活动状态异常||活动没有开始||活动已经结束
                //秒杀失败的信息,将数据保存到秒杀记录表中,封装成秒杀记录的数据,转发到死信队列中
                rabbitTemplate.convertAndSend(SYS.SK_EXCHANGE, SYS.SK_DLX_ROUTING_KEY, message);
                //结束流程
                return;
            }
            //准备秒杀
            //获取分布式锁
            //某一个秒杀商品的分布式锁的key
            String sk_lock_key=SYS.SK_PRE_LOCK_KEY + skgoodsid;
            boolean lockAcquired = false;
            int retryCount = 0;
            while (!lockAcquired && retryCount < 3) {//尝试获取锁，最多尝试3次
                lockAcquired = vos.setIfAbsent(sk_lock_key,"",SYS.SK_LOCK_EXPIRE_TIME, TimeUnit.MILLISECONDS);
                if (!lockAcquired) {
                    retryCount++;
                    try {
                        Thread.sleep(10); // 短暂等待后重试
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }

            // 如果无法获取锁，将请求转到死信队列
            if (!lockAcquired) {
                rabbitTemplate.convertAndSend(SYS.SK_EXCHANGE, SYS.SK_DLX_ROUTING_KEY, message);
                return;
            }
//            while (!vos.setIfAbsent(sk_lock_key,"",SYS.SK_LOCK_EXPIRE_TIME, TimeUnit.MILLISECONDS));   //76-95代替了这行
            long a=System.currentTimeMillis();
            //检查用户是否已经抢购 --  用户允许抢购的数量是可以在抢购商品中设置的
            if(sos.isMember(SYS.SK_RESULT_GOODS_SET_KEY+skgoodsid,skRequest.getUserid())){
                //已经抢购了
                rabbitTemplate.convertAndSend(SYS.SK_EXCHANGE, SYS.SK_DLX_ROUTING_KEY, message);
                //开放分布式锁
                redisTemplate.delete(sk_lock_key);
                //结束流程
                return;
            }
            //秒杀成功在redis中记录秒杀用户的信息，防止超买
            sos.add(SYS.SK_RESULT_GOODS_SET_KEY+skgoodsid,skRequest.getUserid());

            //检查秒杀商品数量,如果数量不足,转发死信，放弃分布式锁,结束流程
            if (vos.get(sk_goods_key) == null || Integer.parseInt(vos.get(sk_goods_key).toString()) <= 0) {
                //秒杀没有数量，转发死信队列
                rabbitTemplate.convertAndSend(SYS.SK_EXCHANGE, SYS.SK_DLX_ROUTING_KEY, message);
                //释放分布式锁
                redisTemplate.delete(sk_lock_key);
                //结束流程
                return;
            }

            //先扣数量
            redisTemplate.opsForValue().decrement(sk_goods_key);
            //放弃分布式锁
            redisTemplate.delete(sk_lock_key);
            long b=System.currentTimeMillis();
            System.out.println("秒杀成功，耗时："+(b-a));
            //秒杀记录和秒杀订单存储在数据库中
            //封装好SKResult对象
            SeckillResult seckillResult = new SeckillResult();
            seckillResult.setUser_id(skRequest.getUserid());//用户id
            seckillResult.setSeckill_goods_id(skRequest.getSkgoodsid());//秒杀商品id
            seckillResult.setActivity_id(skRequest.getActivityid());//活动id
            seckillResult.setResult(1);//秒杀结果，1成功，0失败
            seckillResult.setId(skRequest.getSkid());//秒杀结果id
            seckillResult.setSeckill_time(LocalDateTime.now());//秒杀时间
            seckillResultService.save(seckillResult);


            //获取秒杀商品数据
            SeckillGoods seckillGoods = seckillGoodsService.getSeckillGoodsById(skRequest.getSkgoodsid());


            //对数据中的数据-1
            seckillGoods.setStock(seckillGoods.getStock()-1);//减库存
            seckillGoodsService.updateSeckillGoods(seckillGoods);
            //根据秒杀商品id获取goods_id，根据goods_id获取goods对象
            Goods goods = goodsService.getGoodsById(seckillGoods.getGoods_id());

            //秒杀订单
            SeckillOrder seckillOrder = new SeckillOrder();//秒杀订单
            seckillOrder.setSeckill_goods_id(seckillGoods.getId());//秒杀商品id
            seckillOrder.setUser_id(skRequest.getUserid());//用户id
            seckillOrder.setActivity_id(skRequest.getActivityid());//活动id
            seckillOrder.setSeckill_goods_name(goods.getName());//秒杀商品名称
            seckillOrder.setSeckill_goods_price(seckillGoods.getSeckill_price());//秒杀商品价格
            seckillOrder.setDelivery_addr_id(delivery_addr_id);//收货地址id
            seckillOrder.setStatus(0);//秒杀订单状态(0:未支付,1:已支付,2:已发货,3:已完成)
            seckillOrder.setCreate_time(LocalDateTime.now());//创建时间
            SeckillOrder seckillOrder1 = seckillOrderService.addSeckillOrder1(seckillOrder);
            System.out.println("秒杀订单ID：" + seckillOrder1.getId());

            // 创建订单地址
            OrderAddr orderAddr = new OrderAddr();
            orderAddr.setUser_id(skRequest.getUserid());//用户id
            orderAddr.setSeckill_goods_id(seckillGoods.getId());//秒杀商品id
            // 根据delivery_addr_id获取收货地址对象
            DeliveryAddr deliveryAddr = deliveryAddrService.getAddrById(delivery_addr_id);
            // 设置订单收货地址
            orderAddr.setAddress(deliveryAddr.getProvince() + deliveryAddr.getCity() + deliveryAddr.getDistrict() + deliveryAddr.getDetail_addr());
            orderAddr.setIs_del(0);

            System.out.println("保存前OrderAddr ID: " + orderAddr.getId());
            OrderAddr orderAddr1 = orderAddrService.addOrderAddr(orderAddr);
            System.out.println("调用addOrderAddr后OrderAddr ID: " + orderAddr1.getId());

            // 根据秒杀订单id更新秒杀订单
            SeckillOrder seckillOrder2 = seckillOrderService.getSeckillOrderById(seckillOrder1.getId());
            seckillOrder2.setOrder_addr_id(orderAddr1.getId());//订单地址id
            int result = seckillOrderService.updateSeckillOrder(seckillOrder2);
            System.out.println("更新秒杀订单结果：" + result);
        }catch(Exception e){
            //失败,将消息转到死信队列
            rabbitTemplate.convertAndSend(SYS.SK_EXCHANGE, SYS.SK_DLX_ROUTING_KEY, message);
            System.out.println("23123213213");
//            throw new ServiceException(e.getMessage());
        }
    }
    /**
     * 监听死信队列  秒杀失败的消息队列
     * @param message
     */
    @RabbitListener(queues=SYS.SK_DLX_QUEUE)
    public void consumerDLXMessage(String message){
        //在秒杀记录表中添加一条秒杀失败的记录
        try {
            SKRequest skRequest = JSON.parseObject(message, SKRequest.class);
            SeckillResult seckillResult = new SeckillResult();
            seckillResult.setId(skRequest.getSkid());
            seckillResult.setUser_id(skRequest.getUserid());
            seckillResult.setSeckill_goods_id(skRequest.getSkgoodsid());
            seckillResult.setActivity_id(skRequest.getActivityid());
            seckillResult.setResult(0); // 秒杀失败
            seckillResult.setSeckill_time(LocalDateTime.now());
            seckillResultService.save(seckillResult);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
